package com.huli.utils.lock;

import com.huli.exception.CustomException;
import com.huli.exception.ExceptionEnum;
import com.huli.utils.Result;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Component
public class RedisLock {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private int lockTimeout = 20000;

    private ThreadLocal<String> thisUuid = new ThreadLocal();

    private ThreadLocal<Integer> lockTimes = new ThreadLocal();

    public void lock(String key) {
        String uuid = UUID.randomUUID().toString();
        long start = System.currentTimeMillis();
        while (true) {
            if (thisUuid.get() != null) {
                lockTimes.set(lockTimes.get() + 1);
                break;
            }
            Boolean bool = redisTemplate.opsForValue().setIfAbsent(key, uuid, 20, TimeUnit.SECONDS);
            if (bool) {
                thisUuid.set(uuid);
                lockTimes.set(1);
                break;
            }
            if (System.currentTimeMillis() - start >= lockTimeout) {
                throw new CustomException(Result.failedResult(ExceptionEnum.REDIS_TIMEOUT));
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    public void unLock(String key) {
        String uuid = redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotEmpty(uuid)) {
            String myUuid = thisUuid.get();
            if (uuid.equals(myUuid)) {
                if (lockTimes.get() <= 1) {
                    redisTemplate.delete(key);
                    lockTimes.set(null);
                    thisUuid.set(null);
                } else {
                    lockTimes.set(lockTimes.get() - 1);
                }
            }
        }
    }
}
